﻿using HPSocketCS;
using log4net;
using McsUtility;
using McsUtility.Models;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using TomNet.Redis;

namespace NodeServer.Common
{
    public partial class TcpForwardServer
    {
        ILog logger = LogManager.GetLogger(typeof(TcpForwardServer));
        //private static readonly object locker = new object();
        /// <summary>
        /// 本地IP
        /// </summary>
        public string LocalIp { get; set; }

        /// <summary>
        /// 本地端口
        /// </summary>
        public ushort LocalPort { get; set; }

        /// <summary>
        /// 服务器Ip
        /// </summary>
        public string ServerIp { get; set; }

        /// <summary>
        /// 服务器端口
        /// </summary>
        public ushort ServerPort { get; set; }

        /// <summary>
        /// 最大连接量
        /// </summary>
        public int MaxConnectionCount { get; set; }

       // private int LoginQueue = 0;

        public uint ConnectionCount
        {
            get { return server.ConnectionCount; }
        }

        public bool AgentIsStarted
        {
            get
            {
                return agent.IsStarted && connIdForAgent != IntPtr.Zero;
            }
        }

        public bool ServerIsStarted
        {
            get
            {
                return server.IsStarted;
            }
        }

        public event EventHandler<MsgEventArgs> OnMessage;
        public event EventHandler<EventArgs> OnShutdown;

        private Task ObserverTask;
        private CancellationTokenSource ObserverTokenSource;

        //private Task ObserverTaskMinerClose;
        //private CancellationTokenSource ObserverTokenSourceMinerClose;

        protected TcpPackAgent agent = new TcpPackAgent();
        protected TcpPackServer server = new TcpPackServer();

        //Agent唯一的一个连接
        private IntPtr connIdForAgent = IntPtr.Zero;

        Extra<ConnExtraData> serverExtra = new Extra<ConnExtraData>();

        private bool forceClose = false;

        private RedisClient redisClient;
        private RedisClient redisClientD1;
        private ConcurrentDictionary<int, int> minersConnID;
        //private List<MinerCloseModel> MinerCloseList = new List<MinerCloseModel>();
        public TcpForwardServer()
        {
            // 设置服务器事件  

            server.MaxPackSize = 0x1000;
            server.PackHeaderFlag = 0xff;
            server.OnPrepareListen += new TcpServerEvent.OnPrepareListenEventHandler(OnServerPrepareListen);
            server.OnAccept += new TcpServerEvent.OnAcceptEventHandler(OnServerAccept);
            server.OnSend += new TcpServerEvent.OnSendEventHandler(OnServerSend);
            server.OnReceive += new TcpServerEvent.OnReceiveEventHandler(OnServerReceive);
            server.OnClose += new TcpServerEvent.OnCloseEventHandler(OnServerClose);
            server.OnShutdown += new TcpServerEvent.OnShutdownEventHandler(OnServerShutdown);
            


            // 设置Client事件         
            agent.MaxPackSize = 0x1000;
            agent.PackHeaderFlag = 0xff;
            agent.OnPrepareConnect += new TcpAgentEvent.OnPrepareConnectEventHandler(OnAgentPrepareConnect);
            agent.OnConnect += new TcpAgentEvent.OnConnectEventHandler(OnAgentConnect);
            agent.OnSend += new TcpAgentEvent.OnSendEventHandler(OnAgentSend);
            agent.OnReceive += new TcpAgentEvent.OnReceiveEventHandler(OnAgentReceive);
            agent.OnClose += new TcpAgentEvent.OnCloseEventHandler(OnAgentClose);
            agent.OnShutdown += new TcpAgentEvent.OnShutdownEventHandler(OnAgentShutdown);
            
            redisClient = new RedisClient();
            minersConnID = new ConcurrentDictionary<int, int>();
            redisClientD1 = new RedisClient(1);

        }

        private void InternalInit()
        {
            forceClose = false;
            server.MaxConnectionCount = (uint)this.MaxConnectionCount + 1000;


        }


        public bool Start()
        {
            if (string.IsNullOrEmpty(LocalIp)
                || string.IsNullOrEmpty(ServerIp)
                || LocalPort == 0
                || ServerPort == 0)
            {
                throw new Exception("请先设置属性[LocalIp,ServerIp,LocalPort,ServerPort]");
            }

            InternalInit();

            server.IpAddress = "0.0.0.0";
            server.Port = LocalPort;
            bool success = server.Start();
            if (success == false)
            {
                //AddMsg(string.Format(" > Server start fail -> {0}({1})", server.ErrorMessage, server.ErrorCode));
                return success;
            }

            success = agent.Start("0.0.0.0", false);
            if (success == false)
            {
                //AddMsg(string.Format(" > Agent start fail -> {0}({1})", agent.ErrorMessage, agent.ErrorCode));
            }


            AgentConnServer();

            success = connIdForAgent != IntPtr.Zero;

            if (!success) { Stop(); };
            StartObserver();
            //StartObserverMinerClose();
            return success;
        }

        private void AgentConnServer()
        {
            IntPtr connId = IntPtr.Zero;

            if (agent.Connect(ServerIp, ServerPort, ref connId) == false)
            {
                if (agent.Connect(ServerIp, ServerPort, ref connId) == false)
                {
                    if (agent.Connect(ServerIp, ServerPort, ref connId) == false)
                    {
                        connIdForAgent = IntPtr.Zero;
                        return;
                    }
                }
            }
            connIdForAgent = connId;
            try
            {
                GetNodeServerResponseModel m = new GetNodeServerResponseModel();
                m.ConnID = connId.ToInt32();
                m.IP = this.LocalIp;
                m.Port = this.LocalPort;
                var responseComm = ProtocolHelper.WritePackage<GetNodeServerResponseModel>(ProtoType.NodeServerInfoToCommServer, m);
                agent.Send(connIdForAgent, responseComm, responseComm.Length);
            }
            catch (Exception e)
            {
                connIdForAgent = IntPtr.Zero;
                logger.Error("AgentConnServer>" + e.Message);
            }
        }
        public bool Stop()
        {
            StopObserver();
            forceClose = true;
            Shutdown();
            return server.Stop() && agent.Stop();
        }

        private void AddMsg(string msg)
        {
            OnMessage?.Invoke(this, new MsgEventArgs(msg));
        }

        private void Shutdown()
        {
            OnShutdown?.Invoke(this, new EventArgs());
        }

        private bool AgentSend(byte[] package)
        {
            if (!AgentIsStarted)
            {
                return false;
            }
            return agent.Send(connIdForAgent, package, package.Length);
        }


        #region 服务器事件
        protected virtual HandleResult OnServerPrepareListen(IntPtr soListen)
        {
            return HandleResult.Ok;
        }

        protected virtual HandleResult OnServerAccept(IntPtr connId, IntPtr pClient)
        {
            //if (LoginQueue > 100)
            //{
            //    return HandleResult.Error;
            //}

            //增加一个未激活的连接           
            //AddMsg(string.Format(" > [{0},OnServerAccept]", connId));
            try
            {
                ConnExtraData extra = new ConnExtraData();
                extra.ConnId = connId.ToInt32();
                extra.Activated = false;
                extra.ConnTime = DateTime.Now;
                extra.CalculatingTime = Convert.ToDateTime("2000-01-01");
                if (serverExtra.Set(connId, extra))
                {
                    return HandleResult.Ok;
                }
                return HandleResult.Error;
            }
            catch (Exception e)
            {
                logger.Error("OnServerAccept>" + e.Message);
                return HandleResult.Error;

            }
        }

        protected virtual HandleResult OnServerSend(IntPtr connId, byte[] bytes)
        {
            return HandleResult.Ok;
        }


        protected virtual HandleResult OnServerReceive(IntPtr connId, byte[] bytes)
        {
            try
            {

                var extra = serverExtra.Get(connId);
                if (extra.Activated)//已经登录
                {
                    //AddMsg(" > [已登录，处理数据]");
                    var proto = ProtocolHelper.GetProtoType(bytes, body: out byte[] body);
                    switch (proto)
                    {
                        case ProtoType.MinerManagerGetCurrencysInfo://刷新钱包矿池信息
                            return MinerManagerGetCurrencysInfo(connId, body, extra);
                        case ProtoType.MinerManagerAddWallets://添加钱包
                            return MinerManagerAddWallets(connId, body, extra);
                        case ProtoType.MinerManagerAddOrePools://添加矿池
                            return MinerManagerAddOrePools(connId, body, extra);
                        case ProtoType.MinerManagerDelWallets://删除钱包
                            return MinerManagerDelWallets(connId, body, extra);
                        case ProtoType.MinerManagerDelOrePools://删除矿池
                            return MinerManagerDelOrePools(connId, body, extra);
                        case ProtoType.MinerManagerModifyWallets://修改钱包
                            return MinerManagerModifyWallets(connId, body, extra);
                        case ProtoType.MinerManagerModifyOrePools://修改矿池
                            return MinerManagerModifyOrePools(connId, body, extra);
                        case ProtoType.MinerManagerGetMiners://获取矿工
                            return MinerManagerGetMiners(connId, body, extra);
                        case ProtoType.MinerManagerModifyOrePoolUrl://修改矿工挖矿信息
                            return MinerManagerModifyOrePoolUrl(connId, body, extra);
                        case ProtoType.MinerManagerModifyBatch://修改矿工挖矿信息
                            return MinerManagerModifyBatch(connId, body, extra);
                        case ProtoType.MinerManagerStartMining://让矿工开始挖矿
                            return MinerManagerStartMining(connId, body, extra);
                        case ProtoType.MinerManagerEndMining://让矿工停止挖矿
                            return MinerManagerEndMining(connId, body, extra);
                        case ProtoType.MinerManagerReset://矿工重启电脑
                            return MinerManagerReset(connId, body, extra);
                        case ProtoType.MinerClientStartMining://开始挖矿
                            return MinerClientStartMining(connId, body, extra);
                        case ProtoType.MinerClientStopMining://停止挖矿
                            return MinerClientStopMining(connId, body, extra);
                        case ProtoType.MinerClientSendData://矿工同步数据
                            return MinerClientSendData(connId, body, extra);
                        case ProtoType.MinerManagerGetRedisData://同步Redis数据
                            return MinerManagerGetRedisData(connId, body, extra);
                        case ProtoType.MinerManagerDelMiner://删除矿工
                            return MinerManagerDelMiner(connId, body, extra);
                        case ProtoType.MinerManagerGetRePassSmsCode://获得修改密码验证码
                            return MinerManagerGetRePassSmsCode(connId, body, extra);
                        case ProtoType.MinerManagerRePass://修改密码
                            return MinerManagerRePass(connId, body, extra);
                        case ProtoType.MinerManagerAddRemark://添加备注
                            return MinerManagerAddRemark(connId, body, extra);
                        case ProtoType.MinerManagerDelRemark://删除备注
                            return MinerManagerDelRemark(connId, body, extra);
                        case ProtoType.MinerManagerModifyRemark://修改备注
                            return MinerManagerModifyRemark(connId, body, extra);
                        case ProtoType.MinerClientWarnToNodeServer://修改备注
                            return MinerClientWarnToNodeServer(connId, body, extra);
                        case ProtoType.MinerManagerGetMinerModel://修改备注
                            return MinerManagerGetMinerModel(connId, body, extra);
                        case ProtoType.MinerClientHeartbeat://心跳
                            return MinerClientHeartbeat(connId, body, extra);
                        case ProtoType.MinerManagerGetLogs://查看日
                            return MinerManagerGetLogs(connId, body, extra);
                        case ProtoType.MinerManagerGetStaffs://查看日
                            return MinerManagerGetStaffs(connId, body, extra);
                        case ProtoType.MinerManagerReStaff://修改业务员
                            return MinerManagerReStaff(connId, body, extra);
                        case ProtoType.MinerManagerGetMinersAll://获得全部矿工
                            return MinerManagerGetMinersAll(connId, body, extra);
                    }
                    return HandleResult.Ok;
                }
                else
                {
                    var proto = ProtocolHelper.GetProtoType(bytes, body: out byte[] body);
                    switch (proto)
                    {
                        case ProtoType.MinerClientLogin://矿工登录
                            return MinerClientLogin(connId, body, extra);
                        case ProtoType.MinerManagerLogin://管理端登录
                        case ProtoType.AppManagerLogin://管理端登录
                            return MinerManagerLogin(connId, body, extra, proto);
                        case ProtoType.MinerManagerGetRegSmsCode://管理端申请注册验证码
                            return MinerManagerGetRegSmsCode(connId, body, extra);
                        case ProtoType.MinerManagerReg://管理端提交注册信息
                            return MinerManagerReg(connId, body, extra);
                        case ProtoType.MinerManagerGetRePassSmsCode://获得修改密码验证码
                            return MinerManagerGetRePassSmsCode(connId, body, extra);
                        case ProtoType.MinerManagerRePass://修改密码
                            return MinerManagerRePass(connId, body, extra);
                        case ProtoType.MinerManagerGetStaffs://查看日
                            return MinerManagerGetStaffs(connId, body, extra);
                        default://非登录协议，断开连接
                            AddMsg(" > [未登录 -> 非登录协议，断开连接]");
                            return HandleResult.Error;
                    }
                }
            }
            catch (Exception e)
            {

                //AddMsg(" > [错误 -> 断开连接:+" + e.Message + "]");
                logger.Error("OnServerReceive>" + e.Message + "]");
                return HandleResult.Ok;
            }

        }

        protected virtual HandleResult OnServerClose(IntPtr connId, SocketOperation enOperation, int errorCode)
        {
            try
            {
                int i;
                var extra = serverExtra.Get(connId);
                if (extra.ClientType == ClientType.MinerClient)
                {
                    minersConnID.TryGetValue(extra.MinerID, out i);
                    if (i == connId.ToInt32())
                    {
                        minersConnID.TryRemove(extra.MinerID, out i);
                    }
                    //MCSSQL.DBUtility.DAL.MinersRequest(3, extra.MinerID, extra.UserID);
                }
                LoginResultForCommServerModel m = new LoginResultForCommServerModel();
                m.connID = connId.ToInt32();
                m.UserID = extra.UserID;
                m.MinerID = extra.MinerID;
                m.ClientType = extra.ClientType;
                m.MinerName = extra.MinerName;
                m.Name = extra.Name;
                //lock (locker)
                //{
                //    MinerCloseList.Add(m);
                //}
                var responseComm = ProtocolHelper.WritePackage<LoginResultForCommServerModel>(ProtoType.MinerCloseCommServer, m);

                agent.Send(connIdForAgent, responseComm, responseComm.Length);

                serverExtra.Remove(connId);
                //if (errorCode == 0)
                //{
                //    AddMsg(string.Format(" > [{0},OnClose]", connId));
                //}
                //else
                //{
                //    AddMsg(string.Format(" > [{0},OnError] -> OP:{1},CODE:{2}", connId, enOperation, errorCode));
                //}
            }
            catch (Exception ex)
            {
                logger.Error("OnServerClose>" + ex.Message);
            }
            return HandleResult.Ok;
        }

        protected virtual HandleResult OnServerShutdown()
        {
            //AddMsg(" > [OnServerShutdown]");
            return HandleResult.Ok;
        }

        #endregion

        #region agent事件
        protected virtual HandleResult OnAgentPrepareConnect(IntPtr connId, IntPtr socket)
        {
            return HandleResult.Ok;
        }

        protected virtual HandleResult OnAgentConnect(IntPtr connId)
        {
            //AddMsg(string.Format(" > [{0},OnAgentConnect]", connId));
            return HandleResult.Ok;
        }

        protected virtual HandleResult OnAgentSend(IntPtr connId, byte[] bytes)
        {
            return HandleResult.Ok;
        }

        protected virtual HandleResult OnAgentReceive(IntPtr connId, byte[] bytes)
        {
            try
            {
                var proto = ProtocolHelper.GetProtoType(bytes, body: out byte[] body);
                switch (proto)
                {
                    case ProtoType.CommServerGetNodeServer://得到可连接NodeServer
                        return CommServerGetNodeServer(connId, body);
                    case ProtoType.CommServerMinerManagerModifyOrePoolUrl://修改挖矿信息
                        return CommServerMinerManagerModifyOrePoolUrl(connId, body);
                    case ProtoType.CommServerMinerManagerModifyBatch://批量修改挖矿信息
                        return CommServerMinerManagerModifyBatch(connId, body);
                    case ProtoType.CommServerMinerManagerStartMining://开始挖矿
                        return CommServerMinerManagerStartMining(connId, body);
                    case ProtoType.CommServerMinerManagerEndMining://停止挖矿
                        return CommServerMinerManagerEndMining(connId, body);
                    case ProtoType.CommServerMinerManagerReset://重启
                        return CommServerMinerManagerReset(connId, body);
                    case ProtoType.CommServerMinerLogoutToNodeServer://CommServer下发矿机离线信息给NodeServer
                        return CommServerMinerLogoutToNodeServer(connId, body);
                    case ProtoType.CommServerMinerLoginToNodeServer://CommServer下发矿机离线信息给NodeServer
                        return CommServerMinerLoginToNodeServer(connId, body);
                    case ProtoType.MinerClientEndMiningToNodeServer://矿机挖矿状态下发给NodeServer
                        return MinerClientEndMiningToNodeServer(connId, body);
                    case ProtoType.MinerClientStartMiningToNodeServer:///矿机挖矿状态下发给NodeServer
                        return MinerClientStartMiningToNodeServer(connId, body);
                    case ProtoType.CommServerWarnToNodeServer:///矿机挖矿状态下发给NodeServer
                        return CommServerWarnToNodeServer(connId, body);
                    case ProtoType.MinerManagerDownToNodeServer:///新管理端登录踢掉老管理端
                        return MinerManagerDownToNodeServer(connId, body);
                    case ProtoType.MinerCloseToNodeServerr:///掉线通知NodeServer
                        return MinerCloseToNodeServerr(connId, body);
                    default:
                        break;
                }
            }
            catch (Exception ex)
            {
                logger.Error("OnAgentReceive>" + ex.Message);
            }

            return HandleResult.Ok;
        }

        protected virtual HandleResult OnAgentClose(IntPtr connId, SocketOperation enOperation, int errorCode)
        {
            //if (errorCode == 0)
            //{
            //    AddMsg(string.Format(" > [{0},OnAgentClose]", connId));
            //}
            //else
            //{
            //    AddMsg(string.Format(" > [{0},OnAgentClose] -> OP:{1},CODE:{2}", connId, enOperation, errorCode));
            //}
            try
            {
                connIdForAgent = IntPtr.Zero;
                if (!forceClose)//异常掉线，这里做重连操作
                {
                    Task.Factory.StartNew(() =>
                    {
                        IntPtr newConnId = IntPtr.Zero;
                        var times = 0;
                        while (times < 300)//十分钟连接不上，就停止服务
                        {
                            Thread.Sleep(1000 * 2);// 两秒重新连接一次
                                                   //AddMsg(" > [异常掉线，这里做重连操作]");
                            if (agent.Connect(ServerIp, ServerPort, ref newConnId))
                            {
                                connIdForAgent = newConnId;
                                try
                                {
                                    GetNodeServerResponseModel m = new GetNodeServerResponseModel();
                                    m.ConnID = connId.ToInt32();
                                    m.IP = this.LocalIp;
                                    m.Port = this.LocalPort;
                                    var responseComm = ProtocolHelper.WritePackage<GetNodeServerResponseModel>(ProtoType.NodeServerInfoToCommServer, m);
                                    agent.Send(connIdForAgent, responseComm, responseComm.Length);
                                }
                                catch (Exception e)
                                {
                                    connIdForAgent = IntPtr.Zero;
                                    logger.Error("OnAgentClose>AgentConnServer>" + e.Message);
                                }

                                var ids = server.GetAllConnectionIDs();
                                if (ids != null)
                                {
                                    foreach (var item in ids)
                                    {
                                        var extra = serverExtra.Get(item);
                                        LoginResultForCommServerModel m = new LoginResultForCommServerModel();
                                        m.ClientType = extra.ClientType;
                                        m.connID = item.ToInt32();
                                        m.Name = extra.Name;
                                        m.UserID = extra.UserID;
                                        m.MinerID = extra.MinerID;
                                        m.MinerName = extra.MinerName;
                                        var responseComm = ProtocolHelper.WritePackage<LoginResultForCommServerModel>(ProtoType.MinerLoginCommServer, m);
                                        agent.Send(connIdForAgent, responseComm, responseComm.Length);
                                    }
                                }
                                return;
                            }
                        }

                        if (connIdForAgent == IntPtr.Zero)
                        {
                            AddMsg(" > [10分钟连接失败，关闭服务器]");
                            Stop();
                        }
                    });
                }
            }
            catch (Exception ex)
            {
                logger.Error("OnAgentClose>" + ex.Message);
            }
            return HandleResult.Ok;
        }

        protected virtual HandleResult OnAgentShutdown()
        {
            //AddMsg(" > [OnAgentShutdown]");
            return HandleResult.Ok;
        }
        #endregion

        #region 守护线程
        private void StartObserver()
        {
            StopObserver();
            ObserverTokenSource = new CancellationTokenSource();
            ObserverTask = Task.Factory.StartNew(ObserverWork, ObserverTokenSource.Token);
        }
        private void StopObserver()
        {
            if (ObserverTokenSource != null)
            {
                if (ObserverTask.Status == TaskStatus.Running)
                {
                    ObserverTokenSource.Cancel();
                }
            }
        }

        private void ObserverWork()
        {
            //判断是否取消任务
            while (!ObserverTokenSource.IsCancellationRequested)
            {
                try
                {
                    var ids = server.GetAllConnectionIDs();
                    if (ids != null)
                    {
                        foreach (var item in ids)
                        {
                            var data = serverExtra.Get(item);
                            if (data == null)
                            {
                                server.Disconnect(item, true);
                            }
                            else if (!data.Activated && DateTime.Now.Subtract(data.ConnTime).TotalSeconds > 120)
                            {
                                server.Disconnect(item, true);
                            }
                            else if (data.Activated && DateTime.Now.Subtract(data.HeartbeatTime).TotalSeconds > 30 && !redisClientD1.KeyExists("H" + data.MinerID) && data.ClientType == ClientType.MinerClient)
                            {
                                //logger.Debug(data.Activated.ToString() + "=" + data.HeartbeatTime.ToString("yyyy-MM-dd HH:mm:ss") + "=" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "=" + data.ClientType.ToString() + "=" + (!redisClientD1.KeyExists("H" + data.MinerID)).ToString());
                                MCSSQL.DBUtility.DAL.MinersRequest(3, data.MinerID, data.UserID);
                                server.Disconnect(item, true);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    logger.Error("守护线程>" + ex.Message);
                }
                AddMsg("连接数：" + server.ConnectionCount);
                Thread.Sleep(10 * 1000);
            }
        }

        #endregion

        //#region 守护线程MinerClose
        //private void StartObserverMinerClose()
        //{
        //    StopObserverMinerClose();
        //    ObserverTokenSourceMinerClose = new CancellationTokenSource();
        //    ObserverTaskMinerClose = Task.Factory.StartNew(ObserverWorkMinerClose, ObserverTokenSourceMinerClose.Token);
        //}
        //private void StopObserverMinerClose()
        //{
        //    if (ObserverTokenSourceMinerClose != null)
        //    {
        //        if (ObserverTaskMinerClose.Status == TaskStatus.Running)
        //        {
        //            ObserverTokenSourceMinerClose.Cancel();
        //        }
        //    }
        //}

        //private void ObserverWorkMinerClose()
        //{
        //    //判断是否取消任务
        //    while (!ObserverTokenSourceMinerClose.IsCancellationRequested)
        //    {
        //        try
        //        {
        //            if (MinerCloseList.Count > 0)
        //            {
        //                var m = MinerCloseList[0];
        //                if (m != null)
        //                {
        //                    MCSSQL.DBUtility.DAL.MinersRequest(3, m.MinerID, m.UserID);
        //                    var responseComm = ProtocolHelper.WritePackage<MinerCloseModel>(ProtoType.MinerCloseCommServer, m);
        //                    if (!agent.Send(connIdForAgent, responseComm, responseComm.Length))
        //                    {
        //                        agent.Send(connIdForAgent, responseComm, responseComm.Length);
        //                    }
        //                }
        //                lock (locker)
        //                {
        //                    MinerCloseList.RemoveAt(0);
        //                }

        //            }
        //            Thread.Sleep(100);
        //        }
        //        catch (Exception ex)
        //        {
        //            logger.Error(ex.Message);
        //        }
        //    }
        //}

        //#endregion

    }

    public class ConnExtraData
    {
        public int ConnId { get; set; }
        public bool Activated { get; set; }
        public int UserID { get; set; }
        public string Name { get; set; }
        public int MinerID { get; set; }
        public string MinerName { get; set; }
        public ClientType ClientType { get; set; }
        public DateTime ConnTime { get; set; }
        public DateTime HeartbeatTime { get; set; }
        public DateTime CalculatingTime { get; set; }//落盘时间
    }
}
